home *** CD-ROM | disk | FTP | other *** search
- /*
- File: DTS_SCSI_Application.c
-
-
-
-
- Unfortunately, no matter how long awaited, it's still not done. In fact, this
- isn't even a release- this is just an image of the code taken in the middle of
- development.
-
- THIS CODE DOES NOT WORK AS A WHOLE. MUCH OF IT IS BUGGY AND / OR INCOMPLETE.
- YOU WOULD HAVE TO BE ABSOLUTELY INSANE TO USE ANY OF THIS CODE IN YOUR
- PROJECT WITHOUT EXTENSIVE THOUGHT, DEBUGGING AND TESTING.
-
-
-
-
-
-
- Contains: All application-level code for DTS' SCSI Sample.
-
- Written by: Colleen Delgadillo, Dennis Hescox, Kent Sandvik, Bryan Stearns
-
- Copyright: © 1992 by Apple Computer, Inc., all rights reserved.
-
- Change History (most recent first):
-
- 7/22/92 ckd Changed Kent's cursor handling to SetCursor.
- 7/14/92 khs Added code for handling the cursor.
- 3/10/92 BJS Added header; messed with comments.
-
- To Do:
- Add busy cursor rotation.
-
- Notes:
- This application was based on Apple's aptly-named simple sample
- application, Sample. For simplicity, some of the comments in the
- original code dealing with general Macintosh development issues
- have been removed -- instead, we concentrate here on the SCSI
- issues. See the original Sample source (included with MPW, etc.)
- if you need background on how a Macintosh application is constructed.
- */
-
- #include <Values.h>
- #include <Types.h>
- #include <Resources.h>
- #include <QuickDraw.h>
- #include <Fonts.h>
- #include <Events.h>
- #include <Windows.h>
- #include <Menus.h>
- #include <TextEdit.h>
- #include <Dialogs.h>
- #include <Desk.h>
- #include <ToolUtils.h>
- #include <Memory.h>
- #include <SegLoad.h>
- #include <Files.h>
- #include <OSUtils.h>
- #include <OSEvents.h>
- #include <DiskInit.h>
- #include <Packages.h>
- #include <Traps.h>
- #ifdef INCLUDEVMCALLS
- #include <GestaltEqu.h>
- extern void NextFunction(); // a dummy function -- tells us where this one ends.
- #endif
-
- #define __FILE_NUMBER__ 0x4000 // Used by assert() when there's no debugger installed
- // to let us know where we're failing
-
- #include "DTS_SCSI_Application.h"
- #include "DTS_SCSI_Format.h"
- #include "DTS_SCSI_Debug.h"
-
-
- /********************************************************************************************
- *
- * Global Variable Definitions
- * (The "g" prefix is used to emphasize that a variable is global.)
- *
- ********************************************************************************************/
-
- // This machine's feature set, set up by Initialize
- SysEnvRec gSysEnvironment;
-
- // Our main dialog window's storage
- DialogRecord gMainDialog;
-
- // Our error-mapping string resource
- ErrorMappingHandle gErrorMappings;
-
-
-
- /********************************************************************************************
- *
- * Handy preprocessor macros.
- *
- * These exist for efficiency and readability, at a cost of clarity: macros can
- * obsure the actual workings of a C program. By clearly documenting these macros,
- * and gathering them together where they can be studied together, we hope to minimize
- * these problems.
- *
- ********************************************************************************************/
-
- // These macros extract the high-order and low-order words of a long integer.
- // They're (much) more efficient than the Toolbox traps.
- #define HiWrd(aLong) (((aLong) >> 16) & 0xFFFF)
- #define LoWrd(aLong) ((aLong) & 0xFFFF)
-
- // These macros allow us to access fields of a rectangle as points.
- #define TopLeft(aRect) (* (Point *) &(aRect).top)
- #define BotRight(aRect) (* (Point *) &(aRect).bottom)
-
-
- /********************************************************************************************
- *
- * Dialog & Alert Utilities
- *
- ********************************************************************************************/
- // *** Kill all pragma statements and document why they have been removed. ??? WHAT/WHY?
- //
- // Enable or disable this dialog control
- //
- void SetDialogItemEnabling(DialogPtr dialog, short item, Boolean enabled) {
- Rect itemBox;
- short itemType;
- ControlHandle itemHandle;
-
- GetDItem(dialog, item, &itemType, (Handle *) &itemHandle, &itemBox);
- HiliteControl(itemHandle, enabled ? 0 : 255);
- }
-
- //
- // Utility routine: Set the text of a dialog item to this Pascal string.
- // (The string must be locked in memory; it may be released after
- // calling this routine.)
- //
- #pragma segment Main
- void SetDialogItemText(DialogPtr dialog, short item, Str255 text) {
- Rect itemBox;
- short itemType;
- Handle itemHandle;
-
- GetDItem(dialog, item, &itemType, &itemHandle, &itemBox);
- SetIText(itemHandle, text);
- } // SetDialogItemText
-
- //
- // Four wrappers for SetDialogItemText: one pair sets the drive info string,
- // the other sets the message string. Within each pair, one accepts the
- // actual text as a parameter; the other gets it from our string list.
- //
- #pragma segment Main
- void PostMessage(Str255 aString) {
- SetDialogItemText((DialogPtr) &gMainDialog, kMessageText, aString);
- }
- #pragma segment Main
- void SetDriveInfoText(Str255 aString) {
- SetDialogItemText((DialogPtr) &gMainDialog, kDriveInfoText, aString);
- }
- #pragma segment Main
- void PostMessageFromList(short index) {
- Str255 tempString;
- GetIndString(tempString, kStringList, index);
- SetDialogItemText((DialogPtr) &gMainDialog, kMessageText, tempString);
- }
- #pragma segment Main
- void SetDriveInfoTextFromList(short index) {
- Str255 tempString;
- GetIndString(tempString, kStringList, index);
- SetDialogItemText((DialogPtr) &gMainDialog, kDriveInfoText, tempString);
- }
-
- //
- // Look up an error string and put its corresponding message in
- // the message string of our main dialog.
- //
- void PostError(short errornumber) {
- short i, errorCount;
- ErrorMapping *thisError;
-
- // Find our error-mapping table resource; figure out how big it is.
- errorCount = SizeResource((Handle) gErrorMappings) / sizeof(ErrorMapping);
-
- // Walk through the table, looking for our error
- for (i = 0, thisError = *gErrorMappings; i < errorCount; i++, thisError++) {
- if (thisError->errNum == errornumber) { // found it!
- HLock((Handle) gErrorMappings);
- PostMessage(thisError->message);
- HUnlock((Handle) gErrorMappings);
- return;
- }
- }
- // We didn't find the message we needed! Substitute a generic one.
- // *** it'd be nice to include the number here.
- PostMessageFromList(kUnknownLowLevelError);
- } // PostError
-
-
- //
- // Draw procedure for the userItems in our main dialog.
- // It simply frames the item's box; if the item happens to be one-dimensional,
- // it appears as a line.
- //
- pascal void FrameUserItems(DialogPtr dialog, short item) {
- Rect itemBox;
- short dummyType;
- Handle dummyHandle;
-
- // Get the box, set the pen, frame the box; the port's already set.
- GetDItem(dialog, item, &dummyType, &dummyHandle, &itemBox);
- PenSize(1,1);
- FrameRect(&itemBox);
- }
-
- /********************************************************************************************
- *
- * Events and Commands
- *
- ********************************************************************************************/
-
- //
- // Put up our About box.
- //
- // We don't bother checking for memory errors here because
- // in this simple application, we don't have documents; we
- // can only be called from the main event loop, when we've
- // got beaucoup free RAM.
- //
- void DoAbout() {
- DialogPtr dialog;
- short item = 0;
-
- // Get the dialog
- dialog = GetNewDialog(kAboutBox, NULL, (WindowPtr) -1L);
-
- assert(dialog != 0,"\Couldn't get the about box window");
-
- if (dialog != NULL) {
- // Let the user run it until he or she clicks OK
- ShowWindow(dialog);
- SetPort(dialog);
- while (item != 1)
- ModalDialog(NULL,&item);
-
- DisposDialog(dialog);
- } else {
- // *** Should we SysBeep when we fail? It should never happen.
- }
- } // DoAbout
-
- //
- // Switch to the next eligible drive, if we can find one.
- // If we can, put its ID in the SCSI device text item (*** eventually,
- // try to get its volume name (if any)). If we can't find an eligible drive,
- // put an appropriate error message in the message text. Either way, set the
- // enabling of the buttons in our window appropriately.
- //
- void DoDrive() {
- Str255 number;
- SCSIAddress newDevice;
- Boolean success;
- short anErr;
-
- // Try to find the next drive. This will return 0 if we found a different
- // drive than the current one, kNoMoreDevices
- anErr = NextEligibleDevice(); // try to find the next drive.
- switch (anErr) {
- case noErr: // We found a new drive.
- // Get its SCSI ID and put it in the SCSI Message box
- newDevice = CurrentDevice();
- NumToString(newDevice, number);
- SetDialogItemText((DialogPtr) &gMainDialog, kDriveInfoText, number);
-
- // *** eventually, get the volume name from the drive. For now,
- // just clear the message area
- SetDialogItemText((DialogPtr) &gMainDialog, kMessageText, "");
- break;
-
- case kNoOtherValidDrives: // We couldn't find a drive other than the current one.
- // We don't need to change the enabling of our buttons, or the
- // displayed current drive ID, but we should put up a message saying
- // that this is the only good one we found.
- PostMessageFromList(kOnlyOneOfOurDevice);
- anErr = noErr; // don't disable the buttons.
- break;
-
- default:
- // We didn't find a usable drive.
- SetDialogItemText((DialogPtr) &gMainDialog, kDriveInfoText, "");
- PostMessageFromList(kNoSCSIDevices);
- break;
- }
-
- // Enable or disable the appropriate buttons based on whether we have
- // a valid drive.
- success = (anErr == noErr);
- SetDialogItemEnabling((DialogPtr) &gMainDialog, kTestButton, success);
- SetDialogItemEnabling((DialogPtr) &gMainDialog, kUpdateButton, success);
- SetDialogItemEnabling((DialogPtr) &gMainDialog, kFormatButton, success);
- }
-
- //
- // Ask the user if he/she's sure that this drive should be trashed.
- // Then trash it.
- //
- void DoFormat() {
- short anErr;
-
- // *** Document why we have this!
- #ifdef DEBUG // *** See if the user's holding down the option key
- EventRecord dummy;
- OSEventAvail(0,&dummy);
- #endif
-
- #ifndef DEBUG // For reducing debugging tedium - don't confirm format.
- if (StopAlert(kConfirmFormatAlert, NULL) == ok)
- #endif
- {
- // Attempt to unmount the volume & unload its driver
-
- anErr = UnmountCurrentDevice();
- assert(anErr == noErr,"Couldn't unmount!");
-
- if (anErr) {
- PostMessageFromList(kFormatError);
- // *** StopAlert(kCouldntUnmount, NULL); Why commented out? *** Dialog never got designed
- return;
- }
-
- // Tell the user we be formattin'
- PostMessageFromList(kFormatting);
- DrawDialog((DialogPtr) &gMainDialog); // force an update
-
- // Format the media.
-
- #ifdef DEBUG // For debugging, we only format if the option key is down.
- anErr = noErr;
- if (dummy.modifiers & optionKey)
- #endif
- anErr = FormatCurrentDevice();
-
- // Write a generic partition map and the driver, install the driver,
- // mount the new volume and DIZero it.
- if (anErr == noErr)
- anErr = PartitionCurrentDevice();
-
- // Update the message
- PostMessageFromList(anErr == noErr ? kFormattingCompleted : kFormatError);
- }
- }
-
- //
- // Update the driver on a drive
- //
- void DoUpdate() {
- short err;
-
- // If I was going to confirm that a user wanted to update the driver, I would
- // put the dialog here, but I think having the newest driver is always the
- // best thing, and because there's little risk of data loss, doesn't need to
- // be confirmed. Ideally, the updater would read the version of the driver
- // on the disk and compare it to this version, asking for confirmation if
- // the version being replaced was newer then the one being installed.
-
- // First, we'll unmount and unload the current driver
- err = UnmountCurrentDevice();
- assert(!err,"Couldn't unmount for updating");
-
- if (err)
- { // *** Put the alert here (maybe one consistant error alert?)
- PostMessageFromList(kUpdateError);
- return;
- }
-
- // Tell the user we're updating the driver and get it drawn
- PostMessageFromList(kUpdating);
- DrawDialog((DialogPtr) &gMainDialog);
-
- // Go off and actually do the update.
- err = UpdateCurrentDevice();
-
- if (err == noErr)
- PostMessageFromList(kUpdateCompleted);
- else
- PostMessageFromList(kUpdateError);
- }
-
- //
- // Our main event loop
- //
- #pragma segment Main
- void MainEventLoop() {
- Boolean done = false;
- short item;
-
- SetPort((DialogPtr) &gMainDialog); // Make sure we're in the right port
- do {
- ModalDialog(NULL, &item);
-
- switch (item) {
- case kAboutButton:
- DoAbout();
- break;
-
- case kFormatButton:
- SetCursor(*GetCursor(watchCursor));
- DoFormat();
- SetCursor(&qd.arrow);
- break;
-
- case kUpdateButton:
- DoUpdate();
- break;
-
- case kDriveButton:
- DoDrive();
- break;
-
- case kQuitButton:
- done = true;
- break;
- }
- } while (!done);
- } // MainEventLoop
-
-
- /********************************************************************************************
- *
- * Initialization
- *
- ********************************************************************************************/
-
-
- //
- // Is this trap implemented?
- // (Note that this depends on gSysEnvironment)
- //
- #pragma segment Initialize
- Boolean TrapAvailable(short trapNumber, TrapType trapType) {
- // if we're running on a 512KE, Plus, or SE, the tool traps only go to 0x1FF
- if ((trapType == ToolTrap) &&
- (gSysEnvironment.machineType > envMachUnknown) &&
- (gSysEnvironment.machineType < envMacII)) {
- // This is a 512KE, Plus, or SE; if the trap is > 0x1ff, it must be unimplemented.
- trapNumber = trapNumber & 0x03FF;
- if (trapNumber > 0x01FF) trapNumber = _Unimplemented;
- }
-
- return NGetTrapAddress(trapNumber, trapType) != GetTrapAddress(_Unimplemented);
- } // TrapAvailable
-
-
- //
- // Report a fatal initialization error to the user, then ExitToShell.
- //
- #pragma segment Initialize
- void FatalInitializationError() {
- SetCursor(&qd.arrow);
- Alert(kInsufficientSystem, nil);
- ExitToShell();
- } // FatalInitializationError
-
-
- // Initialize: Set up the whole world, including global variables, Toolbox managers,
- // and menus. We also create our one application window at this time.
- //
- #pragma segment Initialize
- void Initialize() {
- Rect itemBox;
- short itemType;
- Handle itemHandle;
- short item;
- long total, contig;
- Str255 vendorString, productString, revisionString;
-
- // Initialize the Toolbox
- InitGraf((Ptr) &qd.thePort);
- InitFonts();
- InitWindows();
- InitMenus();
- TEInit();
- InitDialogs(NULL);
- InitCursor();
-
- // Inquire as to our environment. If we don't have 128K ROMs or better,
- // we don't have SCSI. Quit.
- SysEnvirons(curSysEnvVers, &gSysEnvironment);
- if (gSysEnvironment.machineType < 0)
- FatalInitializationError(); // exit
-
- // Do we have enough memory to run?
- PurgeSpace(&total, &contig);
- if (total < kMinimumSpace)
- FatalInitializationError();
-
- // Load our error-mapping table resource and string list. We
- // keep these in memory to simplify our memory management.
- gErrorMappings = (ErrorMappingHandle) GetResource(kErrorMappingResourceType, kErrorMappingResourceID);
- if ((!gErrorMappings) || (!GetResource('STR#', kStringList)))
- FatalInitializationError();
-
- // Tell the low-level code what vendor string we're looking for
- GetIndString(vendorString, kStringList, kVendorString);
- GetIndString(productString, kStringList, kProductString);
- GetIndString(revisionString, kStringList, kRevisionString);
- SetValidationInfo(vendorString, productString, revisionString);
-
- // Get our window - if we can't, die.
- if (!GetNewDialog(kMainDialog, &gMainDialog, (WindowPtr) -1L /*in front*/))
- FatalInitializationError();
-
- // Install our userItem's draw procedure
- for (item = kFirstUserItem; item <= kLastUserItem; ++item) {
- GetDItem((DialogPtr) &gMainDialog, item, &itemType, &itemHandle, &itemBox);
- SetDItem((DialogPtr) &gMainDialog, item, itemType, (Handle) FrameUserItems, &itemBox);
- }
-
- // Show the window, and draw it, so that the user has something to look at
- // while we're trolling for qualified devices.
- ShowWindow((DialogPtr) &gMainDialog);
- DrawDialog((DialogPtr) &gMainDialog);
-
- // Find a usable SCSI device and make it the default one.
- DoDrive();
- }
-
-
- //
- // The main entry point:
- // - Get rid of the data-initialization segment, to avoid fragmenting memory
- // - Expand the application heap to its maximum
- // - Finish our initialization
- // - Unload the segment containing our initialization
- // - Run!
- //
- #pragma segment Main
- main() {
- extern void _DataInit();
- UnloadSeg((Ptr) _DataInit); // Unload the data-initialization segment,
- // to avoid fragmenting memory.
-
- MaxApplZone(); // expand the heap so code segments load at the top
- Initialize(); // initialize the program
- UnloadSeg((Ptr) Initialize); // unload the initialization segment
-
- MainEventLoop(); // Run!
-
- // We're going to quit. We could close our main dialog window, but
- // since our heap will be destroyed shortly, why bother?
- // *** OK, we probably should close the dialog window.
- ExitToShell();
- }
-